package com.atguigu.dao.impl;

import com.atguigu.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

//这是给别人复用代码用的,它不需要实例化,需要继承下来--干什么?
public abstract class BaseDao {
    //使用dbutils操作数据库
    private QueryRunner queryRunner=new QueryRunner();

    /**
     * update() 方法用来执行insert update delete语句
     * @return //返回-1表示执行失败,否则就返回影响的行数
     */
    public int update(String sql,Object... args){//Object ...args是可边长参数 这里用于表示sql中?等占位符
        System.out.println("BaseDao程序在["+Thread.currentThread().getName()+"]线程中");
        //update只接收2个参数,一个是sql一个是参数,会被queryRunner自动组合成一个sql去执行,返回行数
        Connection connection= JdbcUtils.getConnection();
        try {
            return queryRunner.update(connection,sql,args);//返回影响的行数
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException(throwables);//这里改成将异常往调用者身上抛的原因是:
            //需要用异常触发调用者身上的回滚机制
            //如果你在自己的类中爆出了异常,那么调用者是不会知道的.也就不会触发调用者身上的回滚机制
        }
        //finally {//这里注释的原因是:使用了事务管理机制,处理完一条sql,不能立刻把连接关闭.
        //因为一旦关闭mysql连接,事务内其他sql将不能使用老的mysql连接,也就不再是同一个事务内的操作了.
        //所以,关闭mysql连接这个事,就不在次次的sql操作中处理了.
        //那么关闭mysql连接这个事,在最后一次sql操作时,由人控制着,来手动提交事务,
        //手动提交,同时关闭mysql连接
        //当然,如果要回滚事务,那么也是要回滚完,同时关闭mysql连接的.
        //    JdbcUtils.close(connection);
        //}

        //return -1;//返回-1表示执行异常
        //注释这一行的原因:正常情况下,会返回影响的行数;异常情况下,会向调用者抛出异常;因此不会用到这一行,所以这一行是无用行.
    }

    /**
     * queryForOne() 方法用于查询一个bean对象
     * @param type 返回的对象类型
     * @param sql  执行的sql
     * @param args sql对应的参数值
     * @param <T> 返回值类型的泛型
     * @return
     */
    public <T> T queryForOne(Class<T> type,String sql,Object... args){//查询返回一个对象
        //第一个T,表示返回值类型
        //第二个T,表示一个类名,用于规范 返回值类型
        Connection con=JdbcUtils.getConnection();
        try {
            //System.out.println(sql);
//            System.out.println(con);
//            System.out.println(sql);
//            System.out.println(new BeanHandler<T>(type));
//            System.out.println(args);
//            System.out.println("BaseDao:50:"+queryRunner.query(con,sql,new BeanHandler<T>(type),args));
            return queryRunner.query(con,sql,new BeanHandler<T>(type),args);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException(throwables);//这里改成将异常往调用者身上抛的原因是:
            //需要用异常触发调用者身上的回滚机制
            //如果你在自己的类中爆出了异常,那么调用者是不会知道的.也就不会触发调用者身上的回滚机制
        }
        //finally {//这里注释的原因是:使用了事务管理机制,处理完一条sql,不能立刻把连接关闭.
        //因为一旦关闭mysql连接,事务内其他sql将不能使用老的mysql连接,也就不再是同一个事务内的操作了.
        //所以,关闭mysql连接这个事,就不在次次的sql操作中处理了.
        //那么关闭mysql连接这个事,在最后一次sql操作时,由人控制着,来手动提交事务,
        //手动提交,同时关闭mysql连接
        //当然,如果要回滚事务,那么也是要回滚完,同时关闭mysql连接的.
        //    JdbcUtils.close(connection);
        //}

        //return -1;//返回-1表示执行异常
        //注释这一行的原因:正常情况下,会返回影响的行数;异常情况下,会向调用者抛出异常;因此不会用到这一行,所以这一行是无用行.
    }

    /**
     * queryForList() 查询返回多个对象
     * @param type 返回的对象类型
     * @param sql  执行的sql
     * @param args sql对应的参数值
     * @param <T> 返回值类型的泛型
     * @return
     */
    public <T> List<T> queryForList(Class<T> type, String sql, Object... args){//查询返回多个对象
        Connection con=JdbcUtils.getConnection();
        try {
            return queryRunner.query(con,sql,new BeanListHandler<T>(type),args);//返回值是一个列表
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException(throwables);//这里改成将异常往调用者身上抛的原因是:
            //需要用异常触发调用者身上的回滚机制
            //如果你在自己的类中爆出了异常,那么调用者是不会知道的.也就不会触发调用者身上的回滚机制
        }
        //finally {//这里注释的原因是:使用了事务管理机制,处理完一条sql,不能立刻把连接关闭.
        //因为一旦关闭mysql连接,事务内其他sql将不能使用老的mysql连接,也就不再是同一个事务内的操作了.
        //所以,关闭mysql连接这个事,就不在次次的sql操作中处理了.
        //那么关闭mysql连接这个事,在最后一次sql操作时,由人控制着,来手动提交事务,
        //手动提交,同时关闭mysql连接
        //当然,如果要回滚事务,那么也是要回滚完,同时关闭mysql连接的.
        //    JdbcUtils.close(connection);
        //}

        //return -1;//返回-1表示执行异常
        //注释这一行的原因:正常情况下,会返回影响的行数;异常情况下,会向调用者抛出异常;因此不会用到这一行,所以这一行是无用行.
    }

    /**
     * 执行一行一列的sql返回一个特定的对象
     * @param sql
     * @param args
     * @return
     */
    public Object queryForSingleValue(String sql, Object... args){//执行一行一列的sql返回一个特定的对象  //这个语句似乎可以返回任何类型的查询
        Connection con=JdbcUtils.getConnection();
        //System.out.println(sql);
        try {
            return queryRunner.query(con,sql ,new ScalarHandler(),args);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException(throwables);//这里改成将异常往调用者身上抛的原因是:
            //需要用异常触发调用者身上的回滚机制
            //如果你在自己的类中爆出了异常,那么调用者是不会知道的.也就不会触发调用者身上的回滚机制
        }
        //finally {//这里注释的原因是:使用了事务管理机制,处理完一条sql,不能立刻把连接关闭.
        //因为一旦关闭mysql连接,事务内其他sql将不能使用老的mysql连接,也就不再是同一个事务内的操作了.
        //所以,关闭mysql连接这个事,就不在次次的sql操作中处理了.
        //那么关闭mysql连接这个事,在最后一次sql操作时,由人控制着,来手动提交事务,
        //手动提交,同时关闭mysql连接
        //当然,如果要回滚事务,那么也是要回滚完,同时关闭mysql连接的.
        //    JdbcUtils.close(connection);
        //}

        //return -1;//返回-1表示执行异常
        //注释这一行的原因:正常情况下,会返回影响的行数;异常情况下,会向调用者抛出异常;因此不会用到这一行,所以这一行是无用行.
    }

}
